package org.homeunix.josivan.gwt.tool.gtic;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;

class StatusFileHandler extends Task {
  protected static final Properties MODULES_STATUS = new SortedProperties();
  protected final File STATUS_FILE;
  private static final String LS = System.getProperty("line.separator");

  private static final String COMMENTS = " Format <moduleName>=(Y|N|D)|LM|LC|TC|(S|F), where: \n"
      + "# S|N|D = Compilable Moduel -> (Y)es | (N)o | (D)isabled, "
      + LS
      + "# LM = (L)ast (M)odification time, "
      + LS
      + "# LC = (L)ast (C)ompilation time, "
      + LS
      + "# TC = Duration of last compilation time, "
      + LS
      + "# S|F = (S)ucess or (F)ailure on last compilation";

  // private static final DateFormat DATE_FORMAT =
  // DateFormat.getDateTimeInstance();

  StatusFileHandler(File outputDir) throws IOException {
    this.STATUS_FILE = new File(outputDir, "gwt.status.history");

    if (!this.STATUS_FILE.exists()) {
      this.STATUS_FILE.createNewFile();
    }
  }

  @Override
  public void execute() throws BuildException {
    super.execute();
  }

  void doUpdateStatusFile() {
    try {
      log("Writing status file...");
      MODULES_STATUS.store(new FileOutputStream(this.STATUS_FILE), COMMENTS);
    } catch (IOException e) {
      throw new BuildException(e);
    }
  }

  static class ModuleData {
    final String values[];
    final String module;
    char status;
    long lc;
    long lm;

    ModuleData(String module) {
      this.module = module;
      this.values = StatusFileHandler.MODULES_STATUS.getProperty(module).split(
          "\\|");
      this.status = this.values[0].charAt(0);
      this.lc = isCompilable() ? Long.parseLong(this.values[2]) : -1;
      this.lm = Long.parseLong(this.values[1]);
    }

    boolean isCompilable() {
      return 'Y' == this.status;
    }

    boolean isDisabled() {
      return this.status == 'D';
    }

    void enable(boolean enable) {
      this.status = enable ? 'S' : 'D';
    }

    void setLastCompilationTime(long lc) {
      this.lc = lc;
    }

    void setLastModificationTime(long lm) {
      this.lm = lm;
    }

    void store() {
      String s = "";

      if (isCompilable() || isDisabled()) {
        s = String.format("%s|%s|%s|%s|%s", this.status, this.lm, this.lc,
            this.values[3], this.values[4]);
      } else {
        s = "N|" + this.lm;
      }

      StatusFileHandler.MODULES_STATUS.put(this.module, s);
    }

    @Override
    public String toString() {
      return String.format("Module %s %scompilable%n modified in %s%s%n.",
          this.module, 
          isCompilable() ? "" : "no-", 
          new Date(this.lm),
          isCompilable() ? " compiled in " + new Date(this.lc) : "");
    }

    boolean recompile() {
      return isCompilable() && this.lc < this.lm;
    }
  }

  static class SortedProperties extends Properties {
    @SuppressWarnings("unchecked")
    @Override
    public synchronized Enumeration keys() {
      Enumeration<Object> keysEnum = super.keys();
      Vector<String> keyList = new Vector<String>();

      while (keysEnum.hasMoreElements()) {
        keyList.add((String) keysEnum.nextElement());
      }

      Collections.sort(keyList);

      return keyList.elements();
    }
  }
}
